home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #9 / Amiga Plus CD - 2004 - No. 09.iso / amigaplus / tools / amigaos4_only / smbfs / source / sock.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-08-03  |  11.2 KB  |  525 lines

  1. /*
  2.  * $Id: sock.c,v 1.19 2004/05/18 08:39:13 obarthel Exp $
  3.  *
  4.  * :ts=8
  5.  *
  6.  * sock.c
  7.  *
  8.  * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
  9.  * Modified by Christian Starkjohann <cs@hal.kph.tuwien.ac.at>
  10.  * Modified for use with AmigaOS by Olaf Barthel <olsen@sourcery.han.de>
  11.  */
  12.  
  13. #include "smbfs.h"
  14.  
  15. /*****************************************************************************/
  16.  
  17. #include <smb/smb_fs.h>
  18. #include <smb/smb.h>
  19. #include <smb/smbno.h>
  20.  
  21. /*****************************************************************************/
  22.  
  23. #include "smb_abstraction.h"
  24.  
  25. /*****************************************************************************/
  26.  
  27. /* smb_receive_raw
  28.    fs points to the correct segment, sock != NULL, target != NULL
  29.    The smb header is only stored if want_header != 0. */
  30. static int
  31. smb_receive_raw (int sock_fd, unsigned char *target, int max_raw_length, int want_header)
  32. {
  33.   int len, result;
  34.   int already_read;
  35.   unsigned char peek_buf[4];
  36.  
  37.  re_recv:
  38.  
  39.   result = recvfrom (sock_fd, (void *) peek_buf, 4, 0, NULL, NULL);
  40.   if (result < 0)
  41.   {
  42.     LOG (("smb_receive_raw: recv error = %ld\n", errno));
  43.     result = (-errno);
  44.     goto out;
  45.   }
  46.  
  47.   if (result < 4)
  48.   {
  49.     LOG (("smb_receive_raw: got less than 4 bytes\n"));
  50.     result = -EIO;
  51.     goto out;
  52.   }
  53.  
  54.   switch (peek_buf[0])
  55.   {
  56.     case 0x00:
  57.     case 0x82:
  58.       break;
  59.  
  60.     case 0x85:
  61.       LOG (("smb_receive_raw: Got SESSION KEEP ALIVE\n"));
  62.       goto re_recv;
  63.  
  64.     default:
  65.       LOG (("smb_receive_raw: Invalid packet 0x%02lx\n", peek_buf[0]));
  66.       result = -EIO;
  67.       goto out;
  68.   }
  69.  
  70.   /* The length in the RFC NB header is the raw data length */
  71.   len = smb_len (peek_buf);
  72.   if (len > max_raw_length)
  73.   {
  74.     LOG (("smb_receive_raw: Received length (%ld) > max_xmit (%ld)!\n", len, max_raw_length));
  75.     result = -EIO;
  76.     goto out;
  77.   }
  78.  
  79.   if (want_header != 0)
  80.   {
  81.     memcpy (target, peek_buf, 4);
  82.     target += 4;
  83.   }
  84.  
  85.   already_read = 0;
  86.  
  87.   while (already_read < len)
  88.   {
  89.     result = recvfrom (sock_fd, (void *) (target + already_read), len - already_read, 0, NULL, NULL);
  90.     if (result < 0)
  91.     {
  92.       LOG (("smb_receive_raw: recvfrom error = %ld\n", errno));
  93.  
  94.       result = (-errno);
  95.  
  96.       goto out;
  97.     }
  98.  
  99.     already_read += result;
  100.   }
  101.  
  102.   result = already_read;
  103.  
  104.  out:
  105.  
  106.   return result;
  107. }
  108.  
  109. /* smb_receive
  110.    fs points to the correct segment, server != NULL, sock!=NULL */
  111. static int
  112. smb_receive (struct smb_server *server, int sock_fd)
  113. {
  114.   byte * packet = server->packet;
  115.   int result;
  116.  
  117.   result = smb_receive_raw (sock_fd, packet,
  118.                             server->max_recv - 4,  /* max_xmit in server includes NB header */
  119.                             1); /* We want the header */
  120.   if (result < 0)
  121.   {
  122.     LOG (("smb_receive: receive error: %ld\n", result));
  123.     goto out;
  124.   }
  125.  
  126.   server->rcls = *((unsigned char *) (packet + 9));
  127.   server->err = WVAL (packet, 11);
  128.  
  129.   if (server->rcls != 0)
  130.     LOG (("smb_receive: rcls=%ld, err=%ld\n", server->rcls, server->err));
  131.  
  132.  out:
  133.  
  134.   return result;
  135. }
  136.  
  137. /* smb_receive's preconditions also apply here. */
  138. static int
  139. smb_receive_trans2 (struct smb_server *server, int sock_fd, int *data_len, int *param_len, char **data, char **param)
  140. {
  141.   unsigned char *inbuf = server->packet;
  142.   int total_data;
  143.   int total_param;
  144.   int result;
  145.  
  146.   LOG (("smb_receive_trans2: enter\n"));
  147.  
  148.   (*data_len) = (*param_len) = 0;
  149.   (*param) = (*data) = NULL;
  150.  
  151.   result = smb_receive (server, sock_fd);
  152.   if (result < 0)
  153.     goto fail;
  154.  
  155.   if (server->rcls != 0)
  156.     goto fail;
  157.  
  158.   /* parse out the lengths */
  159.   total_data = WVAL (inbuf, smb_tdrcnt);
  160.   total_param = WVAL (inbuf, smb_tprcnt);
  161.  
  162.   if ((total_data > server->max_xmit) || (total_param > server->max_xmit))
  163.   {
  164.     LOG (("smb_receive_trans2: data/param too long\n"));
  165.  
  166.     result = -EIO;
  167.     goto fail;
  168.   }
  169.  
  170.   /* Allocate it, but only if there is something to allocate
  171.      in the first place. ZZZ this may not be the proper approach,
  172.      and we should return an error for 'no data'. */
  173.   if(total_data > 0)
  174.   {
  175.     (*data) = malloc (total_data);
  176.     if ((*data) == NULL)
  177.     {
  178.       LOG (("smb_receive_trans2: could not alloc data area\n"));
  179.  
  180.       result = -ENOMEM;
  181.       goto fail;
  182.     }
  183.   }
  184.   else
  185.   {
  186.     (*data) = NULL;
  187.   }
  188.  
  189.   /* Allocate it, but only if there is something to allocate
  190.      in the first place. ZZZ this may not be the proper approach,
  191.      and we should return an error for 'no parameters'. */
  192.   if(total_param > 0)
  193.   {
  194.     (*param) = malloc(total_param);
  195.     if ((*param) == NULL)
  196.     {
  197.       LOG (("smb_receive_trans2: could not alloc param area\n"));
  198.  
  199.       result = -ENOMEM;
  200.       goto fail;
  201.     }
  202.   }
  203.   else
  204.   {
  205.     (*param) = NULL;
  206.   }
  207.  
  208.   LOG (("smb_rec_trans2: total_data/param: %ld/%ld\n", total_data, total_param));
  209.  
  210.   while (1)
  211.   {
  212.     if (WVAL (inbuf, smb_prdisp) + WVAL (inbuf, smb_prcnt) > (unsigned int)total_param)
  213.     {
  214.       LOG (("smb_receive_trans2: invalid parameters\n"));
  215.       result = -EIO;
  216.       goto fail;
  217.     }
  218.  
  219.     if((*param) != NULL)
  220.       memcpy ((*param) + WVAL (inbuf, smb_prdisp), smb_base (inbuf) + WVAL (inbuf, smb_proff), WVAL (inbuf, smb_prcnt));
  221.  
  222.     (*param_len) += WVAL (inbuf, smb_prcnt);
  223.  
  224.     if (WVAL (inbuf, smb_drdisp) + WVAL (inbuf, smb_drcnt) > (unsigned int)total_data)
  225.     {
  226.       LOG (("smb_receive_trans2: invalid data block\n"));
  227.       result = -EIO;
  228.       goto fail;
  229.     }
  230.  
  231.     if((*data) != NULL)
  232.       memcpy ((*data) + WVAL (inbuf, smb_drdisp), smb_base (inbuf) + WVAL (inbuf, smb_droff), WVAL (inbuf, smb_drcnt));
  233.  
  234.     (*data_len) += WVAL (inbuf, smb_drcnt);
  235.  
  236.     LOG (("smb_rec_trans2: drcnt/prcnt: %ld/%ld\n", WVAL (inbuf, smb_drcnt), WVAL (inbuf, smb_prcnt)));
  237.  
  238.     /* parse out the total lengths again - they can shrink! */
  239.     if ((WVAL (inbuf, smb_tdrcnt) > (unsigned int)total_data) || (WVAL (inbuf, smb_tprcnt) > (unsigned int)total_param))
  240.     {
  241.       LOG (("smb_receive_trans2: data/params grew!\n"));
  242.       result = -EIO;
  243.       goto fail;
  244.     }
  245.  
  246.     total_data = WVAL (inbuf, smb_tdrcnt);
  247.     total_param = WVAL (inbuf, smb_tprcnt);
  248.     if (total_data <= (*data_len) && total_param <= (*param_len))
  249.       break;
  250.  
  251.     result = smb_receive (server, sock_fd);
  252.     if (result < 0)
  253.       goto fail;
  254.  
  255.     if (server->rcls != 0)
  256.     {
  257.       result = -EIO;
  258.       goto fail;
  259.     }
  260.   }
  261.  
  262.   LOG (("smb_receive_trans2: normal exit\n"));
  263.   return 0;
  264.  
  265.  fail:
  266.  
  267.   LOG (("smb_receive_trans2: failed exit\n"));
  268.  
  269.   if((*param) != NULL)
  270.     free (*param);
  271.  
  272.   if((*data) != NULL)
  273.     free (*data);
  274.  
  275.   (*param) = (*data) = NULL;
  276.  
  277.   return result;
  278. }
  279.  
  280. int
  281. smb_release (struct smb_server *server)
  282. {
  283.   int result;
  284.  
  285.   if (server->mount_data.fd >= 0)
  286.     CloseSocket (server->mount_data.fd);
  287.  
  288.   server->mount_data.fd = socket (AF_INET, SOCK_STREAM, 0);
  289.   if (server->mount_data.fd < 0)
  290.   {
  291.     result = (-errno);
  292.     goto out;
  293.   }
  294.  
  295.   result = 0;
  296.  
  297.  out:
  298.  
  299.   return result;
  300. }
  301.  
  302. int
  303. smb_connect (struct smb_server *server)
  304. {
  305.   int sock_fd = server->mount_data.fd;
  306.   int result;
  307.  
  308.   if (sock_fd < 0)
  309.   {
  310.     result = (-EBADF);
  311.     goto out;
  312.   }
  313.  
  314.   result = connect (sock_fd, (struct sockaddr *)&server->mount_data.addr, sizeof(struct sockaddr_in));
  315.   if(result < 0)
  316.     result = (-errno);
  317.  
  318.  out:
  319.  
  320.   return(result);
  321. }
  322.  
  323. /*****************************************************************************
  324.  *
  325.  *  This routine was once taken from nfs, which is for udp. Here TCP does
  326.  *  most of the ugly stuff for us (thanks, Alan!)
  327.  *
  328.  ****************************************************************************/
  329.  
  330. int
  331. smb_request (struct smb_server *server)
  332. {
  333.   int len, result;
  334.   int sock_fd = server->mount_data.fd;
  335.   unsigned char *buffer = server->packet;
  336.  
  337.   if ((sock_fd < 0) || (buffer == NULL))
  338.   {
  339.     LOG (("smb_request: Bad server!\n"));
  340.     result = -EBADF;
  341.     goto out;
  342.   }
  343.  
  344.   if (server->state != CONN_VALID)
  345.   {
  346.     result = -EIO;
  347.     goto out;
  348.   }
  349.  
  350.   len = smb_len (buffer) + 4;
  351.  
  352.   LOG (("smb_request: len = %ld cmd = 0x%lx\n", len, buffer[8]));
  353.  
  354.   result = send (sock_fd, (void *) buffer, len, 0);
  355.   if (result < 0)
  356.   {
  357.     LOG (("smb_request: send error = %ld\n", errno));
  358.  
  359.     result = (-errno);
  360.   }
  361.   else
  362.   {
  363.     result = smb_receive (server, sock_fd);
  364.   }
  365.  
  366.  out:
  367.  
  368.   if (result < 0)
  369.   {
  370.     server->state = CONN_INVALID;
  371.     smb_invalidate_all_inodes (server);
  372.   }
  373.  
  374.   LOG (("smb_request: result = %ld\n", result));
  375.  
  376.   return (result);
  377. }
  378.  
  379. /* This is not really a trans2 request, we assume that you only have
  380.    one packet to send. */
  381. int
  382. smb_trans2_request (struct smb_server *server, int *data_len, int *param_len, char **data, char **param)
  383. {
  384.   int len, result;
  385.   int sock_fd = server->mount_data.fd;
  386.   unsigned char *buffer = server->packet;
  387.  
  388.   if (server->state != CONN_VALID)
  389.   {
  390.     result = -EIO;
  391.     goto out;
  392.   }
  393.  
  394.   len = smb_len (buffer) + 4;
  395.  
  396.   LOG (("smb_request: len = %ld cmd = 0x%02lx\n", len, buffer[8]));
  397.  
  398.   result = send (sock_fd, (void *) buffer, len, 0);
  399.   if (result < 0)
  400.   {
  401.     LOG (("smb_trans2_request: send error = %ld\n", errno));
  402.  
  403.     result = (-errno);
  404.   }
  405.   else
  406.   {
  407.     result = smb_receive_trans2 (server, sock_fd, data_len, param_len, data, param);
  408.   }
  409.  
  410.  out:
  411.  
  412.   if (result < 0)
  413.   {
  414.     server->state = CONN_INVALID;
  415.     smb_invalidate_all_inodes (server);
  416.   }
  417.  
  418.   LOG (("smb_trans2_request: result = %ld\n", result));
  419.  
  420.   return result;
  421. }
  422.  
  423. /* target must be in user space */
  424. int
  425. smb_request_read_raw (struct smb_server *server, unsigned char *target, int max_len)
  426. {
  427.   int len, result;
  428.   int sock_fd = server->mount_data.fd;
  429.   unsigned char *buffer = server->packet;
  430.  
  431.   if (server->state != CONN_VALID)
  432.   {
  433.     result = -EIO;
  434.     goto out;
  435.   }
  436.  
  437.   len = smb_len (buffer) + 4;
  438.  
  439.   LOG (("smb_request_read_raw: len = %ld cmd = 0x%02lx\n", len, buffer[8]));
  440.   LOG (("smb_request_read_raw: target=%lx, max_len=%ld\n", (unsigned int) target, max_len));
  441.   LOG (("smb_request_read_raw: buffer=%lx, sock=%lx\n", (unsigned int) buffer, (unsigned int) sock_fd));
  442.  
  443.   result = send (sock_fd, (void *) buffer, len, 0);
  444.  
  445.   LOG (("smb_request_read_raw: send returned %ld\n", result));
  446.  
  447.   if (result < 0)
  448.   {
  449.     LOG (("smb_request_read_raw: send error = %ld\n", errno));
  450.  
  451.     result = (-errno);
  452.   }
  453.   else
  454.   {
  455.     result = smb_receive_raw (sock_fd, target, max_len, 0);
  456.   }
  457.  
  458.  out:
  459.  
  460.   if (result < 0)
  461.   {
  462.     server->state = CONN_INVALID;
  463.     smb_invalidate_all_inodes (server);
  464.   }
  465.  
  466.   LOG (("smb_request_read_raw: result = %ld\n", result));
  467.  
  468.   return result;
  469. }
  470.  
  471. /* Source must be in user space. smb_request_write_raw assumes that
  472.    the request SMBwriteBraw has been completed successfully, so that
  473.    we can send the raw data now. */
  474. int
  475. smb_request_write_raw (struct smb_server *server, unsigned const char *source, int length)
  476. {
  477.   int result;
  478.   byte nb_header[4];
  479.   int sock_fd = server->mount_data.fd;
  480.  
  481.   if (server->state != CONN_VALID)
  482.   {
  483.     result = -EIO;
  484.     goto out;
  485.   }
  486.  
  487.   smb_encode_smb_length (nb_header, length);
  488.  
  489.   result = send (sock_fd, (void *) nb_header, 4, 0);
  490.   if (result == 4)
  491.   {
  492.     result = send (sock_fd, (void *) source, length, 0);
  493.     if(result < 0)
  494.       result = (-errno);
  495.   }
  496.   else
  497.   {
  498.     if(result < 0)
  499.       result = (-errno);
  500.     else
  501.       result = -EIO;
  502.   }
  503.  
  504.   LOG (("smb_request_write_raw: send returned %ld\n", result));
  505.  
  506.   if (result == length)
  507.     result = smb_receive (server, sock_fd);
  508.  
  509.  out:
  510.  
  511.   if (result < 0)
  512.   {
  513.     server->state = CONN_INVALID;
  514.  
  515.     smb_invalidate_all_inodes (server);
  516.   }
  517.  
  518.   if (result > 0)
  519.     result = length;
  520.  
  521.   LOG (("smb_request_write_raw: result = %ld\n", result));
  522.  
  523.   return result;
  524. }
  525.